#ifndef __MY_UTIL__
#define __MY_UTIL__
#include<iostream>
#include<fstream>
#include<sstream>
#include<memory>
#include<string>
#include<sys/stat.h>
#include<experimental/filesystem>
#include"jsoncpp/json/json.h"
#include"bundle.h"



namespace cloud
{
    namespace fs=std::experimental::filesystem;
    class FileUtil
    {
    public:
        FileUtil(const std::string filename)
            :_filename(filename)
        {}

        bool Remove()
        {
            return remove(_filename.c_str())==0;
        }

        int64_t FileSize()const
        {
            struct stat st;

            if(stat(_filename.c_str(),&st)<0)
            {
                std::cerr<<"get file filesize failed!"<<std::endl;
                return -1;
            }

            return st.st_size;



        }

        time_t LastATime()
        {
            struct stat st;

            if(stat(_filename.c_str(),&st)<0)
            {
                std::cerr<<"get file LastATime failed!"<<std::endl;
                return -1;
            }

            return st.st_atime;
        }

         time_t LastMTime()
        {
            struct stat st;

            if(stat(_filename.c_str(),&st)<0)
            {
                std::cerr<<"get file LastMTime failed!"<<std::endl;
                return -1;
            }

            return st.st_mtime;
        }

        std::string FileName()
        {
            size_t pos=_filename.find_last_of("/");
            if(pos==_filename.npos)
            {
                return _filename;
            }

            return _filename.substr(pos+1);
        }

        bool GetPosLen(std::string* body,size_t pos,size_t len)
        {
            if(pos+len>FileSize())
            {
                std::cerr<<"pos+len超过了文件长度"<<std::endl;
                return false;
            }

            std::ifstream ifs;
            ifs.open(_filename,std::ios::binary);
            if(!ifs.is_open())
            {
                std::cerr<<"read file open fail"<<std::endl;
                return false;
            }
            ifs.seekg(pos,std::ios::beg);
            body->resize(len);

            ifs.read(&(*body)[0],len);
            if(ifs.good()==false)
            {
                std::cerr<<"get file content fail"<<std::endl;
                ifs.close();
                return false;
            }

            ifs.close();

            return true;
        }

        bool GetContent(std::string* body)
        {
            return GetPosLen(body,0,FileSize());
        }

        bool SetContent(const std::string& body)
        {
            std::ofstream ofs;
            ofs.open(_filename,std::ios::binary);
            if(ofs.is_open()==false)
            {
                std::cerr<<"write file open fail"<<std::endl;
                return false;
            }

            ofs.write(body.c_str(),body.size());
            if(ofs.good()==false)
            {
                std::cerr<<"set file content fail"<<std::endl;
                ofs.close();
                return false;
            }
            ofs.close();

            return true;

        }

        bool Compress(const std::string& packname)
        {
            std::string body;
            if(GetContent(&body)==false)
            {
                std::cout<<"compress get file content fail"<<std::endl;
                return false;
            }

            std::string pack=bundle::pack(bundle::LZIP,body);

            FileUtil file(packname);
            if(file.SetContent(pack)==false)
            {
                std::cout<<"compress write file content fail"<<std::endl;
                return false;
            }

            return true;
        }

        bool UnCompress(const std::string& unpackname)
        {
            std::string body;
            if(GetContent(&body)==false)
            {
                std::cout<<"uncompress get file content fail"<<std::endl;
                return false;
            }

            std::string unpack=bundle::unpack(body);

            FileUtil file(unpackname);
            if(file.SetContent(unpack)==false)
            {
                std::cout<<"uncompress write file content fail"<<std::endl;
                return false;
            }

            return true;
        }

        bool Exists()const
        {
            return fs::exists(_filename);
        }

        bool CreateDirectory()
        {
            if(Exists())
                return true;
            return fs::create_directories(_filename);
        }

        bool ScanDirectory(std::vector<std::string>* arr)
        {
            for(auto& e: fs::directory_iterator(_filename))
            {
                if(!fs::is_directory(e))
                {
                    arr->push_back(fs::path(e).relative_path().string());
                }
            }

            return true;
        }

    private:
        std::string _filename;
    };


    class JsonUtil
    {
    public:
        static bool Serialize(const Json::Value& root,std::string* str)
        {
            Json::StreamWriterBuilder swb;
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
            std::stringstream ss;
            if(sw->write(root,&ss)!=0)
            {
                std::cout<<"Serialize error"<<std::endl;
                return false;
            }


            *str=ss.str();
            return true;

        }

        static bool UnSerialize(const std::string& str,Json::Value* root)
        {
            Json::CharReaderBuilder crb;
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
            std::string err;
            if(cr->parse(str.c_str(),str.c_str()+str.size(),root,&err)==false)
            {
                std::cout<<"parse error:"<<err<<std::endl;
                return false;
            }

            return true;
            
        }

    };
}

#endif